#include <ctype.h>
#include "data_structure.h"
#include "boosting_manager.h"

#include <algorithm>
using namespace std;

#define Malloc(type,n) (type *)malloc((n)*sizeof(type))

void read_problem(const char *filename, boosting_problem & prob, boosting_node *& x_space) 
{
	int elements, max_index, i, j;
	fpos_t position;
	FILE *fp = fopen(filename,"r");
	
	if(fp == NULL)
	{
		fprintf(stderr,"can't open input file %s\n",filename);
		exit(1);
	}

	fgetpos (fp, &position);

	prob.l = 0;
	elements = 0;
	while(1)
	{
		int c = fgetc(fp);
		switch(c)
		{
			case '\n':
				++prob.l;
			case ':':
				++elements;
				break;
			case EOF:
				goto out;
			default:
				;
		}
	}
out:
	fsetpos (fp, &position);

	prob.y = Malloc(double,prob.l);
	prob.x = Malloc(struct boosting_node *,prob.l);
	x_space = Malloc(struct boosting_node,elements);

	if(prob.y == NULL || prob.x == NULL || x_space == NULL) {
		double ynum = sizeof(double) * prob.l / (1024 * 1024.0);
		double xnum = sizeof(struct boosting_node) * prob.l / (1024 * 1024.0);
		double spacenum = sizeof(struct boosting_node) * elements / (1024 * 1024.0);
		fprintf(stderr,"Virtual Memory should be at least %f MB!\n", ynum + xnum + spacenum);
		exit(1);
	}

	max_index = 0;
	j=0;
	for(i=0;i<prob.l;i++)
	{
		double label;
		prob.x[i] = &x_space[j];
		fscanf(fp,"%lf",&label);
		prob.y[i] = label;

		while(1)
		{
			int c;
			do {
				c = getc(fp);
				if(c=='\n') goto out2;
			} while(isspace(c));
			ungetc(c,fp);
			if (fscanf(fp,"%d:%lf",&(x_space[j].index),&(x_space[j].value)) < 2)
			{
				fprintf(stderr,"last c is |%c|\n", c);
				fprintf(stderr,"Wrong input format at line %d\n", i+1);
				exit(1);
			}
			++j;
		}	
out2:
		if(j>=1 && x_space[j-1].index > max_index)
			max_index = x_space[j-1].index;
		x_space[j++].index = -1;
	}

	fclose(fp);
}

int find_dim(boosting_node ** xx, int l) {
	int dim = -1;
	for(int i = 0; i < l; i++) {
		boosting_node * x = xx[i];
		while(x->index != -1) {
			if(x->index > dim) {
				dim = x->index;
			}
			x++;
		}
	}
	return dim;
}

int main_train(int argc, char ** argv) {

	if(argc < 6) {
		printf("usage: exe train model layer algorithm base\n");
		return 0;
	}

	char * train_file = argv[1];
	char * model_file = argv[2];
	int layer = atoi(argv[3]);
	char * algorithm_type = argv[4];
	char * base_type = argv[5];

	boosting_manager bm;
	bm.train_initialize(layer, algorithm_type, base_type);

	boosting_problem prob;
	boosting_node * x_space;
	read_problem(train_file, prob, x_space);
	prob.dim = find_dim(prob.x, prob.l);

	argc -= 6;
	argv += 6;

	bm.train(prob, argc, argv);
	bm.dump(model_file);

	free(prob.y);
	free(prob.x);
	free(x_space);

	return 1;
}
